package entity;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;

/**
 *This is the Poem class.  
 */
public class Poem extends Movable implements Serializable {
	private static final long serialVersionUID = -2254127298298437681L;
	private static int nextId = 0;
	
	private int id;
	private ArrayList<Row> rows;
	private Date publishedOn;

	/**
	 * Constructor of Poem. A poem is composed of rows.
	 */
	public Poem(int id, ArrayList<Row> rows) {
		this.id = id;
		this.rows = rows;
		this.publishedOn = null;
	}

	/**
	 * Constructor of Poem. A poem is composed of one row.
	 */
	public Poem(int id, Row row) {
		this.id = id;
		this.rows = new ArrayList<Row>();
		this.rows.add(row);
		this.publishedOn = null;
	}

	/**
	 * Constructor of Poem. A poem is composed of another poem.
	 */
	public Poem(Poem p) {
		this.rows = new ArrayList<Row>();
		this.id = p.getId();
		this.publishedOn = p.getPublishedOn();
		
		for(Row r : p.getRows()){
			this.rows.add(new Row(r));
		}
	}
	
	public Poem clone(){
		return new Poem(this);
	}
	
	/**
	 * Add a row to a poem. 
	 * You can add the row to the top or the bottom of the poem. 
	 */
	public void addRow(Row row, Edge e) {
		if (e == Edge.TOP) {
			rows.add(0,row);
		} else if (e == Edge.BOTTOM) {
			rows.add(row);
		}
	}
	
	/**
	 * Add one poem to another poem. 
	 * You can add the poem to the top or the bottom of that poem. 
	 */
	public void addPoem(Poem poem, Edge e) {
		if (e == Edge.TOP) {
			for (int i = 0; i < poem.getRows().size(); i++) {
				rows.add(i, poem.getRows().get(i));
			}
		} else if (e == Edge.BOTTOM) {
			for (Row r : poem.getRows()) {
				rows.add(r);
			}
		}
	}
	
	/**
	 * Remove a row from a poem.
	 */
	public void removeRow(Row r) {
		rows.remove(r);
	}
	
	/**
	 * Shift a row in a poem.
	 */
	public void shiftRow(Row r, int x) {

	}
	
	/**
	 * Check whether a word overlaps a poem.
	 */
	public boolean checkCollision(Word w) {
		for (Row r : rows) {
			if (r.checkCollision(w)) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Return the next row of a specific row.
	 */
	public Row nextRow(Row r) {
		Row next = null;
		
		if (rows.contains(r)) {
			next = rows.indexOf(r) < rows.size() - 1 ? rows.get(rows.indexOf(r) + 1) : null;
		}
		
		return next;
	}
	
	/**
	 * Return the previous row of a specific row.
	 */
	public Row previousRow(Row r) {
		Row prev = null;
		
		if (rows.contains(r)) {
			prev = rows.indexOf(r) > 0 ? rows.get(rows.indexOf(r) - 1) : null;
		}
		
		return prev;
	}
	
	/**
	 * Set position for the poem by setting position for rows and words in the poem.
	 */
	public void setPosition(int x, int y) {
		int nextRowX = x;
		int nextRowY = y;
		
		for (Row r : rows) {
			nextRowX = x + r.getOffsetX();
			
			r.setPosition(nextRowX, nextRowY);
			
			nextRowY += r.getWords().get(0).getHeight() + 2;
		}
	}
	
	/**
	 * Reset position for the poem.
	 */
	public void rearrange() {
		int nextRowX = getX();
		int nextRowY = getY();
		
		for (Row r : rows) {
			r.setOffsetX(r.getX() - getX());
			
			nextRowX = getX() + r.getOffsetX();
			r.setPosition(nextRowX, nextRowY);
			nextRowY += r.getWords().get(0).getHeight() + 2;
			
			r.rearrange();
		}
	}
	
	/**
	 * Return the position of X direction of the first word in the first row in a poem.
	 */
	public int getX() {
		return rows.get(0).getWords().get(0).getX();
	}
	
	/**
	 * Return the position of Y direction of the first word in the first row in a poem.
	 */
	public int getY() {
		return rows.get(0).getWords().get(0).getY();
	}
	
	/**
	 * Return the total height of a poem.
	 */
	public int getHeight() {
		Row firstRow = rows.get(0);
		Row lastRow = rows.get(rows.size() - 1);
		
		int totalHeight = (lastRow.getY() + lastRow.getHeight()) - firstRow.getY();
		
		return totalHeight;
	}
	
	/**
	 * Return the total width of a poem.
	 */
	public int getWidth() {
		int totalWidth = 0;
		
		for (Row r : rows) {
			int rowWidth = r.getWidth() + r.getOffsetX();
			totalWidth = totalWidth > rowWidth ? totalWidth : rowWidth;
		}
		
		return totalWidth;
	}
	
	/**
	 * Get rows in a poem.
	 */
	public ArrayList<Row> getRows() {
		return rows;
	}
	
	/**
	 * Get the row in a poem that contains a specific word. 
	 */
	public Row rowThatContains(Word w) {
		Row result = null;
		
		for (Row r : rows) {
			if (r.contains(w)) {
				result = r;
				break;
			}
		}
		
		return result;
	}
	
	/**
	 * Check whether the poem contains a specific row.
	 */
	public boolean contains(Row r) {
		return rows.contains(r);
	}
	
	/**
	 * Check whether a poem is equals to another word, in terms of not only value, but also all other attributes. 
	 */
	@Override
	public boolean equals(Object o) {
		return o instanceof Poem && id == ((Poem) o).getId();
	}
	
	/**
	 * Check whether the poem contains a specific word.
	 */
	public boolean contains(Word w) {
		for (Row r : rows){
			if (r.contains(w)) {
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Return the string value of every word in a poem.
	 */
	public String toString() {
		String result = "Poem:\n";
		
		for (Row r : rows) {
			result += r.toString() + ("\n");
		}
		
		return result;
	}
	
	public ArrayList<Word> getWords(){
		ArrayList<Word> list = new ArrayList<Word>();
		
		for(Row r : rows){
			list.addAll(r.getWords());
		}
		
		return list;
	}

	/**
	 * Get ID of a poem.
	 */
	public int getId() {
		return id;
	}

	/**
	 * Set ID for a poem.
	 */
	public void setId(int id) {
		this.id = id;
	}
	
	public static int nextId(){
		return nextId++;
	}

	public Date getPublishedOn() {
		return publishedOn;
	}

	public void setPublishedOn(Date publishedOn) {
		this.publishedOn = publishedOn;
	}
}
